import tensorflow as tf
import keras
import numpy as np
import matplotlib.pyplot as plt

import utils

(train_data,train_labels),(test_data,test_labels) = keras.datasets.boston_housing.load_data()
#np.random.random 返回在0.0到1.0之间指定个数的随机浮点数
#argsort返回排序的索引，目的搞乱数据
order = np.argsort(np.random.random(train_labels.shape))
train_data = train_data[order]
train_labels = train_labels[order]

#归一化处理 减去均值再除以标准差 收敛数据 减轻训练
mean = train_data.mean(axis=0)
std = train_data.std(axis=0)
train_data = (train_data - mean) / std
test_data = (test_data - mean) / std

def build_model():
    #tf.nn.relu 激活函数 修正线性单元
    model = keras.Sequential([keras.layers.Dense(64,activation=tf.nn.relu,input_shape=(train_data.shape[1],)),
                     keras.layers.Dense(64,activation=tf.nn.relu),
                     keras.layers.Dense(1)])
    #均方根传播优化器
    optimizer = keras.optimizers.RMSprop(0.001)
    #mse均方差，一般用于回归问题的损失函数
    #mae平均绝对误差，一般用于回归问题的测量、评估
    model.compile(loss='mse',optimizer=optimizer,metrics=['mae'])
    return model

model = build_model()
model.summary()

class PrintDot(keras.callbacks.Callback):
    def on_epoch_end(self, epoch, logs=None):
        if epoch % 100 == 0:print('') #换行
        print('.', end='')

EPOCHS = 2000
#EarlyStopping 降低过拟合 早期停止技术，在迭代patience次内损失值降低 模型性能提升 就停止训练
early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=500)
history = model.fit(train_data, train_labels, epochs=EPOCHS,validation_split=0.2,verbose=0,callbacks=[early_stop,PrintDot()])

def plot_history(history):
    plt.figure()
    plt.xlabel('Epoch')
    plt.ylabel('Mean Abs Error [1000$]')
    plt.plot(history.epoch, np.array(history.history['loss']), label='Train Loss')
    #plt.plot(history.epoch, np.array(history.history['val_mean_absolute_error']), lable='Val loss')
    plt.legend()
    plt.ylim([0,5])
    plt.show()

plot_history(history)

[loss, mae] = model.evaluate(test_data, test_labels, verbose=0)
print("Testing set Mean Abs Error:${:7.2f}".format(mae * 1000))

test_predictions = model.predict(test_data).flatten()
plt.scatter(test_labels, test_predictions)
plt.xlabel('True Valees [1000$]')
plt.ylabel('Predictions [1000$]')
plt.axis('equal')
plt.xlim(plt.xlim())
plt.ylim(plt.ylim())
plt.plot([-100,100],[-100,100])
plt.show()

error_predictions = test_predictions - test_labels
plt.hist(error_predictions, bins=50)
plt.xlabel('Prediction Error [1000$]')
plt.ylabel('Count')
plt.show()

utils.plotVersusFigure(test_labels, test_predictions)